local global = _G.global
local RoleFFI  = require("role.RoleFFI")
local RoleDBLogic  = require("role.RoleDBLogic")
local Timer = require("core.Timer")
local Msg   = require("core.Msg")
local CommonDefine = require("common.CommonDefine")
local FriendDBLogic = require("friend.FriendDBLogic")
local TeamLogic = require("team.TeamLogic")
local FamilyManager = require("family.FamilyManager")
local MailLogicFW = require("mail.MailLogicFW")
local BagHandler = require("bag.HandlerW")
local EquipConf = require("excel.Equip").equip
local sbConfig = require("excel.Shenbing").shenbing
local ItemDefine = require("bag.ItemDefine")
local CopyW = require("copy.CopyW")
local PayLogic = require("admin.PayLogicW")
local HorseConfig = require("excel.Horse")
local StageConfig = HorseConfig.stage
local HuanhuaConfig = HorseConfig.huanhua
local Log = require("common.Log")
local ServerCommonFW = require("serverCommon.ServerCommonFW")
local RoleHandlerW = require("role.HandlerW")
local LvRankLogic = require("rank.LvRankLogic")
local PataRankLogic = require("rank.PataRankLogic")
local TencentCompass = require("tencentApi.Compass")
local Config = require("Config")
local MiddleLogic = require("middle.MiddleLogic")
local MPacketDefine = require("middle.MPacketDefine")
local BaowuConfig = require("excel.Baowu").baowu
local ArmourDefine = require("armour.Define")
local MiddleCopySign = require("middle.MiddleCopySign")
local TaskMarket = require("task.TaskMarket")
local FamilyLogicFW = require("family.FamilyLogicFW")
local RankHandlerW = require("rank.HandlerW")
local OfficialExcel = require("excel.Official").official
-- world 中的在线角色表

local q_cap = 5000
local function q_push(id)
    if q_b + 1 == q_f or q_b == q_cap and q_f == 1 then
        assert()
    end
    q[q_b] = id
    q_b = q_b + 1
    if q_b == q_cap + 1 then
        q_b = 1
    end
end

function q_pop()
    if q_f + 1 == q_b or q_f == q_cap and q_b == 1 then
        assert()
    end
    local t = q[q_f]
    q_f = q_f + 1
    if q_f == q_cap + 1 then
        q_f = 1
    end
    return t
end

local function q_init()
    if q then
        return
    end
    q = {}
    q_b = q_cap
    q_f = 1
    for i = 1, q_cap do
        q[i] = 1000 + i -- 这里的objid从1001开始 0-1000留给客户端的剧情动画角色
    end
end

q_init()


onlineHuman = onlineHuman or {}
onlineAccount = onlineAccount or {}
onlineUuid = onlineUuid or {}
fds = fds or {}   --fd转换成obj_id

destroyList = destroyList or {}


function create(fd, account, db)
    local human = {}

    human.fd = fd
    human.id = q_pop()
    human.uid = Timer.now

    human.db = db or RoleDBLogic.loadRole(account)
    if human.db == nil then
        human.db = RoleDBLogic.createDefaultRole(account, account, 2) -- 帐号不存在 我们用帐号名直接创建一个角色

        print("account:"..account)
    end

    human.db = RoleFFI.create_ffi(human.db, fd, db)      --生成ffi数据
    human.db.ip = global.get_ip_from_fd(human.fd)
    human.db.disconnect = 0
  
    --记录最近一次登录时间
    human.db.lastLoginTime = os.time()

    --小优化
    human._id = RoleFFI.ffi_string(human.db._id)
    human.account = RoleFFI.ffi_string(human.db.account)
    human.name = RoleFFI.ffi_string(human.db.name)
    human.familyUuid = RoleFFI.ffi_string(human.db.familyUuid)
    human.ip = RoleFFI.ffi_string(human.db.ip)
    
    human.familyUuidM =RoleFFI.ffi_string(human.db.familyUuidM)
    human.familyNameM =RoleFFI.ffi_string(human.db.familyNameM)

    --此处为方便L线程中doCalc方法的军团属性加成结算
    if human.familyUuid ~= "" then
        local nFamily = FamilyManager.findByUuid(human.familyUuid)
        if nFamily then
            human.db.familyLv = nFamily.familyLv
            human.db.familyBanner = nFamily.familyBanner
            human.db.familyName = nFamily.familyName
            human.db.familyWarResult = nFamily.middleFamilyResult
            human.familyName = RoleFFI.ffi_string(human.db.familyName)
        else
            human.db.familyWarResult = 0
            human.db.taoyuanVersion = 0
        end
    elseif not Config.IS_MIDDLE then --跨服，不清除
        human.db.familyWarResult = 0
        human.db.familyBanner = 0
        human.db.familyLv = 0  
        human.db.taoyuanVersion = 0
    end

    onlineHuman[human.name] = human
    onlineAccount[human.account] = human
    onlineUuid[human._id] = human
    fds[fd] = human


    human.teamInvite = {}                    --邀请人列表

    human.saveDBTime = Timer.now                -- 人物数据库保存时间
    
    return human
end

function destroy(human)
    if human.db then
        onlineHuman[RoleFFI.ffi_string(human.db.name)] = nil
        onlineAccount[RoleFFI.ffi_string(human.db.account)] = nil
        onlineUuid[RoleFFI.ffi_string(human.db._id)] = nil
        RoleFFI.destroy_ffi(human.db)
        human.db = nil
    end
    q_push(human.id)
end

function disconnect(human, code)
    if human.fd == nil and code == CommonDefine.DISCONNECT_M2G_ERR then --如果存在fd则走正常的代码
         save(human)
         Log.write(Log.LOGID_OSS_LOGOUT, human._id, human.account, human.name, human.db.lv, human.ip, CommonDefine.DISCONNECT_TIME_DESTROY, human.db.map_id, human.x, human.y, Timer.now - human.db.lastLoginTime)
         destroy(human)
         return
    end
    if human.fd == nil then
        return
    end
    if human.db then
      human.db.disconnect = 1
    end
    fds[human.fd] = nil
    if code ~= CommonDefine.DISCONNECT_NORMAL  or code ~= CommonDefine.DISCONNECT_NORMAL_AFTER then
        local mm = Msg.gc.GC_DISCONNECT
        mm.code = code
        mm.msg = CommonDefine.DISCONNECT_MSG[code]
        Msg.send(mm, human.fd)
    end
--    print("W disconnect name:"..account(human), " code:"..code)     
    
    if Config.IS_MIDDLE and code ~= CommonDefine.DISCONNECT_NORMAL and code ~= CommonDefine.DISCONNECT_M2G_ERR then
        sendLogoutMiddleData(human)
    end     
    local msg = Msg.wl.WL_AA_DISCONNECT
    msg.code = code
    Msg.send2logic(msg, human._id)
    
      
    Msg.set_logic(human.fd, human._id)
    human.fd = nil
    human.f5 = Timer.now 
    human.disconnectCode = code
    
    if human.db == nil then
        return
    end
    save(human)
    onLoginOut(human)    
    
    if code == CommonDefine.DISCONNECT_M2G_ERR then
        Log.write(Log.LOGID_OSS_LOGOUT, human._id, human.account, human.name, human.db.lv, human.ip, CommonDefine.DISCONNECT_TIME_DESTROY, human.db.map_id, human.x, human.y, Timer.now - human.db.lastLoginTime)
        destroy(human)
    end
end

-- 向正常服发送M2G_LOGOUT_MIDDLE_DATA
function sendLogoutMiddleData(human)
    if not Config.IS_MIDDLE then return end
    local fd = MiddleLogic.getFDBySvrIndex(human.db.svrIndex)
    if fd then
          _G.msg_middle_parse.writebegin(fd)
          _G.msg_middle_parse.writeint(MPacketDefine.M2G_LOGOUT_MIDDLE_DATA)
          _G.msg_middle_parse.writeint(human.db.svrIndex)
          local db = RoleFFI.get_default_db()
          RoleFFI.copy_ffi_to_db(human.db, db)
          _G.msg_middle_parse.writetable(db)
          _G.msg_middle_parse.writeend()
    end
    
    TeamLogic.exit(human._id) 
end


--登陆时回调
function onLoginIn(human)
    FriendDBLogic.onUserLogin(human)
    FamilyManager.onUserLogin(human)
    TeamLogic.onUserLogin(human)
    MailLogicFW.sendHasNewMail(human)    
    PayLogic.onLogin(human)
    
    print("os.time():", os.time())
    print("ServerCommonFW.getVersionTimeLocal():", ServerCommonFW.getVersionTimeLocal())
    print("human.db.lastLogoutTime:", human.db.lastLogoutTime)
    
    
    
    if os.time() >= ServerCommonFW.getVersionTimeLocal() and human.db.lastLogoutTime < ServerCommonFW.getVersionTimeLocal() then
        RoleHandlerW.CG_SERVER_NOTICE(human, {type = 1}) 
    end
    RankHandlerW.allChange(human)
    TencentCompass.reportLogin(human)
end

--断线即出时回调
function onLoginOut(human)
    human.db.lastLogoutTime = os.time() --记录最近登出时间
    FriendDBLogic.onUserLoginOut(human)
    TeamLogic.onUserLogOut(human)
    FamilyManager.onUserLoginOut(human)
    BagHandler.onUserLoginOut(human)
    BagHandler.cancelSmelt(human)
    CopyW.onLogout(human)    
    MiddleCopySign.onUserLogout(human)
    
    TencentCompass.reportQuit(human)
end




function account(human)
    return RoleFFI.ffi_string(human.db.account)
end

function name(human)
    return RoleFFI.ffi_string(human.db.name)
end


function human1Min()
    for _,human in pairs(onlineUuid) do
		TaskMarket.humanOneMinCheck(human)
    end
end

function save_db()
    local now = Timer.now
    local minn
    local ans
    for _,human in pairs(onlineUuid) do
        if human.fd then
            local t = human.saveDBTime
            if 300000 <= now - t and (not minn or t < minn) then
                minn = t
                ans = human
            end
        end
    end
    if not ans then
        return
    end
    ans.saveDBTime = now
    local ret = pcall(save, ans)
    if not ret then
        --    Log.write(Log.LOGID_ERR_PCALL, "saveCharDB rolename="..ans.db.name, err)
    end
end

function save(human)
    local db  = RoleFFI.get_default_db()
    RoleFFI.copy_ffi_to_db(human.db, db)
    RoleDBLogic.saveRole(db)
end

--这里需要检查，防止L线程异常，报错没有上报LW_AA_DISCONNECT
function humanOfflineCheck()
    for name, human in pairs(onlineHuman) do
        if human.fd == nil then
            if human.f5 == nil or Timer.now - human.f5 > 130000 then
                save(human)
                Log.write(Log.LOGID_OSS_LOGOUT, human._id, human.account, human.name, human.db.lv, human.ip, CommonDefine.DISCONNECT_TIME_DESTROY, human.db.map_id, human.x, human.y, Timer.now - human.db.lastLoginTime)
                if human.disconnectCode and human.disconnectCode == CommonDefine.DISCONNECT_NORMAL then
                    sendLogoutMiddleData(human)
                end
                destroy(human)
                print("World: human offlineCheck")                
            end
        end
    end
end

function getShenbing(db, id)
    for i = 0, db.shenbingLen - 1  do
        if db.shenbing[i].id == id then
            return db.shenbing[i]
        end
    end
end

function getShenbingName(human)
    local sb = sbConfig[human.db.putonShenbing]
    if sb == nil then
        return ""
    end
    return sb.sbMingzi
end

function getRealBodyInfo(db, baowuSource1)
    -- sex equip
    local body = 0
    local weapon = 0
    local weapon2 = 0
    local weaponEffect = 0
    local weapon2Effect =0
    local bone = 0  -- 骨骼
    local bodyEffect = 0
    local horseEffect = 0
    local baowuSource = 0
    local baowuEffect = 0
    local pifeng = 0
    local horse = 0
    local bodyColor = 0
    local head = 0
    local official = 0
    if db.officialLv ~= 0 then
      official = OfficialExcel[db.officialLv].image
    end
    local sb = sbConfig[db.putonShenbing]
    local data = getShenbing(db, db.putonShenbing)    
    if sb and data then
        if data.jinhua == 0 then
          weapon = sb.weaponID[1]
          weaponEffect = sb.weaponEffect[1]
          weapon2 = sb.weaponID2[1]
          weapon2Effect = sb.weaponEffect2[1]
          bone =sb.boneID[1][db.sex]
       else
          weapon = sb.weaponID[2]
          weaponEffect = sb.weaponEffect[2]          
          weapon2 = sb.weaponID2[2]
          weapon2Effect = sb.weaponEffect2[2]
          bone =sb.boneID[2][db.sex]
       end
    else 
       sb = sbConfig[5]       
    end
    if data and data.star <= 0 then
      weaponEffect = 0
      weapon2Effect = 0
    end
    if db.chooseHorseId ~= 0 then
      horseEffect, horse = getHorseInfo(db, db.chooseHorseId)
    end

    local bodyGrid = db.equip[ItemDefine.CLOTH-1]
    local source
    if bodyGrid ~=nil and bodyGrid.id ~= 0 and EquipConf[bodyGrid.id] then
        source = EquipConf[bodyGrid.id].source[db.sex]       
    end
    if source == nil then
        source = db.sex
    end
    body = source

    if db.combatBaowu and db.combatBaowu ~= 0 then
      baowuSource = BaowuConfig[db.combatBaowu].source
      baowuEffect = BaowuConfig[db.combatBaowu].effect 
    end
    if db.curarmourid and db.curarmourid > 0 then
        head, body, pifeng = ArmourDefine.getViewInfo(db.curarmourid, db.sex)
    end
    
    return body,weapon,weaponEffect,pifeng,horse,bone,weapon2,weapon2Effect,bodyEffect,horseEffect,bodyColor,(baowuSource1 and baowuSource1 or baowuSource), baowuEffect, head, official
end

function makeViewInfo(viewInfo, sex, body, weapon, weaponEffect, pifeng,horse, bone, weapon2, weapon2Effect,bodyEffect,horseEffect,bodyColor, baowuSource, baowuEffect, head, official, leftarm, rightarm) 
  viewInfo.sex = sex or 0
  viewInfo.body = body or 0
  viewInfo.bodyEffect = bodyEffect or 0  
  viewInfo.bone = bone or 0
  viewInfo.weapon = weapon or 0
  viewInfo.weaponEffect = weaponEffect or 0
  viewInfo.weapon2 = weapon2 or 0
  viewInfo.weapon2Effect = weapon2Effect or 0
  viewInfo.pifeng = pifeng or 0
  viewInfo.horse = horse or 0
  viewInfo.horseEffect = horseEffect or 0
  viewInfo.bodyColor = bodyColor or 0
  viewInfo.baowuSource = baowuSource or 0
  viewInfo.baowuEffect = baowuEffect or 0
  viewInfo.head = head or 0
  viewInfo.official = official or 0
  viewInfo.leftarm = leftarm or 0
  viewInfo.rightarm = rightarm or 0
end

function getLoginPf(human)
  return human.pf_info.login_pf or human.pf_info.pf
end

--得到当前特效，形象
function getHorseInfo(db, horseId)
  local id = horseId or db.chooseHorseId
  for i=1, #StageConfig do
    if i == id then
      return StageConfig[i].effect, StageConfig[i].source 
    end
  end
  for k,v in pairs(HuanhuaConfig) do
    if k == id then
      return v.effect, v.source
    end
  end
  return 0
end

-- 发送蓝钻信息
function sendBlueInfo(human)
  local msg = Msg.gc.GC_QQ_BLUE_INFO
  msg.blue = human.db.blueVip
  msg.blueLv = human.db.blueVipLv
  msg.blueYear = human.db.blueYearVip
  msg.blueSuper = human.db.blueSuperVip
  Msg.send(msg, human.fd)
end
